package com.hyk.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.hyk.entity.*;
import com.hyk.entity.request.OrderRequest;
import com.hyk.entity.response.OrderResponse;
import com.hyk.enums.ApiEnum;
import com.hyk.enums.OrderEnum;
import com.hyk.exception.GlobalException;
import com.hyk.job.OrderJob;
import com.hyk.mapper.*;
import com.hyk.service.IOrderProductService;
import com.hyk.service.IUserOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hyk.service.PayService;
import com.hyk.utils.AlipayUtil;
import com.hyk.utils.IdWorker;
import com.hyk.utils.UserUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author hyk
 * @since 2021-03-23
 */
@Service
public class UserOrderServiceImpl extends ServiceImpl<UserOrderMapper, UserOrder> implements IUserOrderService {

    @Resource
    private UserOrderMapper orderMapper;

    @Resource
    private ProductMapper productMapper;

    @Resource
    private OrderProductMapper orderProductMapper;

    @Resource
    private IOrderProductService orderProductService;

    @Resource
    private AddressMapper addressMapper;

    @Resource
    private PayService payService;

    @Resource
    private OrderEvaluateMapper orderEvaluateMapper;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public Long getOrder(List<OrderRequest> orderRequests) {

        HttpServletRequest request = ((ServletRequestAttributes)
                                    RequestContextHolder.
                                    currentRequestAttributes()).getRequest();
        LinkedHashMap user = (LinkedHashMap) request.getAttribute("user");
        BigDecimal multiply = BigDecimal.ONE;
        IdWorker worker = new IdWorker(1,1,1);

        List<OrderProduct> orderProducts = Lists.newArrayList();

        for (OrderRequest requestX:orderRequests){
            //查询生成订单的商品
            Product product = productMapper.selectById(requestX.getId());
            multiply = multiply.add(product.getProductPrice().multiply(new BigDecimal(requestX.getNum())));

            //封装订单商品快照表数据
            OrderProduct orderProduct = new OrderProduct();
            BeanUtils.copyProperties(product,orderProduct);
            orderProduct.setId(worker.nextId());
            orderProduct.setProductId(product.getId());
            orderProduct.setProductNum(requestX.getNum());
            orderProduct.setCreateTime(new Date());
            orderProduct.setUpdateTime(new Date());
            orderProducts.add(orderProduct);
        }

        long l = worker.nextId();
        //封装订单
        UserOrder order = new UserOrder();
        order.setId(l);
        order.setUserId(Long.parseLong(user.get("id").toString()));
        order.setOrderStatus(OrderEnum.B.getCode());
        order.setOrderPrice(multiply);
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        orderMapper.insertX(order);

        orderProducts = orderProducts.stream().peek(orderProduct ->
                orderProduct.setOrderId(order.getId())).
                collect(Collectors.toList());

        orderProductService.saveBatch(orderProducts);

        OrderResponse orderResponse = new OrderResponse();
        orderResponse.setId(l);
        orderResponse.setOrderStatus(OrderEnum.B.getCode());
        orderResponse.setOrderPrice(multiply);
        orderResponse.setProducts(orderProducts);
        redisTemplate.opsForValue().set(l+"",orderResponse,30, TimeUnit.MINUTES);

        System.out.println("订单id:"+order.getId());
        return order.getId();
    }

    @Override
    public OrderResponse orderDesc(String id) {
        //尝试从缓存中获取
        OrderResponse response = (OrderResponse) redisTemplate.opsForValue().get(id);

        if (response != null){
            HttpServletRequest request = ((ServletRequestAttributes)
                    RequestContextHolder.
                    currentRequestAttributes()).
                    getRequest();
            LinkedHashMap user = (LinkedHashMap) request.getAttribute("user");
            Address address = addressMapper.selectUserDefaultAddress(Long.parseLong(user.get("id").toString()));
            if (address != null){
                response.setAddress(address);
            }

            return response;
        }

        //查询数据库
        UserOrder userOrder = orderMapper.selectById(id);
        if (userOrder == null){
            throw new GlobalException(ApiEnum.FAIL);
        }

        //根据订单查询所有商品快照
        List<OrderProduct> orderProducts = orderProductMapper.selectOrder(userOrder.getId());

        Address address = addressMapper.selectById(userOrder.getAddressId());
        response = new OrderResponse();
        response.setId(userOrder.getId());
        response.setOrderPrice(userOrder.getOrderPrice());
        response.setOrderStatus(userOrder.getOrderStatus());
        response.setProducts(orderProducts);
        response.setAddress(address);

        redisTemplate.opsForValue().set(userOrder.getId()+"",response,20, TimeUnit.MINUTES);

        return response;
    }

    @Override
    public List<OrderResponse> listOrder() {


        LinkedHashMap user = UserUtils.getUser();

        List<OrderResponse> responses = new ArrayList<>();

        List<UserOrder> userOrders = orderMapper.selectUserOrder(Long.parseLong(user.get("id").toString()));

        for(UserOrder userOrder : userOrders){
            OrderResponse orderResponse = new OrderResponse();
            List<OrderProduct> orderProducts = orderProductMapper.selectOrder(userOrder.getId());
            orderResponse.setProducts(orderProducts);
            orderResponse.setOrderPrice(userOrder.getOrderPrice());
            orderResponse.setId(userOrder.getId());
            orderResponse.setOrderStatus(userOrder.getOrderStatus());
            responses.add(orderResponse);
        }
        return responses;

    }

    @Override
    public String pay(String id, String addressId) throws AlipayApiException {

        UserOrder userOrder = orderMapper.selectById(id);
        redisTemplate.opsForValue().set("address-order"+userOrder.getId(),addressId,15,TimeUnit.MINUTES);
        return payService.aliPay(new AlipayBean().setBody(addressId)
                .setOut_trade_no(userOrder.getId().toString())
                .setTotal_amount(new StringBuffer(userOrder.getOrderPrice().toString()))
                .setSubject(UUID.randomUUID().toString()));

    }

    @Override
    public void changeOrder(OrderEnum c, String orderId) {
        redisTemplate.delete(orderId);
        String addressId = (String) redisTemplate.opsForValue().get("address-order"+orderId);

        UserOrder userOrder = new UserOrder();
        userOrder.setId(Long.parseLong(orderId));
        userOrder.setOrderStatus(c.getCode());
        if (StringUtils.isNotBlank(addressId)){
            userOrder.setAddressId(Long.parseLong(addressId));
        }
        userOrder.setUpdateTime(new Date());
        orderMapper.updateById(userOrder);
        redisTemplate.delete("address-order"+orderId);
    }

    @Override
    public void clearOrder() throws AlipayApiException {
        Date date = DateUtils.addMinutes(new Date(),-15);

        List<UserOrder> userOrders = orderMapper.selectOrderTypeByTime(date,OrderEnum.B.getCode());

        List<UserOrder> b = new ArrayList<>();
        List<UserOrder> c = new ArrayList<>();

        for (UserOrder userOrder:userOrders){
            Map<String,String> map = new HashMap<>();
            map.put("out_trade_no",userOrder.getId().toString());
            AlipayTradeQueryResponse search = AlipayUtil.search(map);

            //判断订单的状态

            //如果不是10000的code   没有点击支付按钮
            if (!search.getCode().equals("10000")){
                userOrder.setUpdateTime(new Date());
                userOrder.setOrderStatus(OrderEnum.A.getCode());
                b.add(userOrder);
                continue;
            }
            // 出现回调接口延时  - 》 修改订单为支付状态
            if (search.getTradeStatus().equalsIgnoreCase("TRADE_SUCCESS")){
                userOrder.setUpdateTime(new Date());
                userOrder.setOrderStatus(OrderEnum.C.getCode());
                c.add(userOrder);
            }
            //  用户 可能是 余额不足  --》  停止支付
            if(search.getTradeStatus().equalsIgnoreCase("WAIT_BUYER_PAY")){
                userOrder.setUpdateTime(new Date());
                userOrder.setOrderStatus(OrderEnum.A.getCode());
                b.add(userOrder);
            }
        }
        //统一更新
        this.updateBatchById(b);
        this.updateBatchById(c);

        redisTemplate.delete(OrderJob.CLEARORDER);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void evaluate(String id, OrderEvaluate orderEvaluate) {
        if (StringUtils.isBlank(id)){
            throw new GlobalException(ApiEnum.FAIL);
        }

        this.changeOrder(OrderEnum.E,id);

        orderEvaluate.setOrderId(Long.parseLong(id));
        orderEvaluate.setCreateTime(new Date());
        orderEvaluate.setUpdateTime(new Date());
        orderEvaluateMapper.insert(orderEvaluate);
    }

    @Override
    public Page<OrderResponse> allListOrder(OrderRequest request) {
        Page<OrderResponse> page = new Page<>(request.getPage(),request.getSize());
        Page<OrderResponse> responsePage = orderMapper.allListPage(page,request);
        return responsePage;
    }

    @Override
    public BigDecimal selectSumToBuy(Date startTime, Date endTime) {
        return orderMapper.sumToBuy(startTime,endTime);
    }

    @Override
    public Integer getOrderSum(int i) {
        if (i == 0){
            return orderMapper.countOrderSum0();
        }else {
            return orderMapper.countOrderSum1();
        }
    }


}
